/*********************************************************************************
 * Software License Agreement (BSD License)
 * Copyright (c) 2012, Carlos D. Correa (info@ngraph.org)
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of netzen nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *********************************************************************************/
#include "layout.h"
#include "graph.h"
#include "controller.h"
#include <assert.h>
#include <math.h>

Layout::Layout(const char*type, const char*name):PropertyBag(type, name) {
	setPropertyString("File", name);
	controller = 0;
	graph = 0;
	graph0 = 0;
	listener = 0;
}

string Layout::PROPERTY(string property) {
	if(controller->isVirtualProperty(property)) {
		return controller->getVirtualProperty(property);
	}
	return property;
}


void Layout::setGraph(Graph *g) {
	assert(g);
	graph = g;
	print("set Graph %s\n", g->getName().c_str());
	vnodes.clear();
	for(unsigned int i=0;i<graph->numNodes();i++) {
		float x = 2*M_PI*(float) i/(float) graph->numNodes();
		NodeInfo n;
		n.x = 0.3*cos(x);
		n.y = 0.3*sin(x);
		n.vx = 0;
		n.vy = 0;
		vnodes.push_back(n);
	}  
	load();
	updateFilter();
}

void Layout::updateFilter() {
	if(!graph) {
//		graph = new Graph();
	}
	//graph = graph0;
}

void Layout::setCreator(string c) {
  creator = c;
}

string Layout::getCreator() {
  return creator;
}

void Layout::getLocation(int i, float &x, float &y){
  x = vnodes[i].x;
  y = vnodes[i].y;
}

void Layout::setLocation(int i, float x, float y){
  vnodes[i].x = x;
  vnodes[i].y = y;
}

void Layout::getVelocity(int i, float &vx, float &vy) {
  vx = vnodes[i].vx;
  vy = vnodes[i].vy;
}
void Layout::setVelocity(int i, float vx, float vy) {
  vnodes[i].vx = vx;
  vnodes[i].vy = vy;
}
void Layout::getForce(int i, float &fx, float &fy) {
  fx = vnodes[i].fx;
  fy = vnodes[i].fy;
}
void Layout::setForce(int i, float fx, float fy) {
  vnodes[i].fx = fx;
  vnodes[i].fy = fy;
}
void Layout::addForce(int i, float fx, float fy) {
  float fx0, fy0;
  getForce(i,fx0,fy0);
  setForce(i,fx0+fx, fy0+fy);
}

void Layout::compute() {
	updated();
}

void Layout::update(string property) {
	if(property=="File") {
		load();
	}
	updated();
}

Layout *createDefaultLayout(string name) {
  Layout *layout = new Layout("Default", name.c_str());
  return layout;
}

void Layout::load() {
	string file = getPropertyString("File");
	FILE *fp = ::fopen(file.c_str(),"r");
	if(!fp) {
            string file2 = "";
            bool retry = this->controller->retryOpenFile(file.c_str(),file2);
            if(!retry){
		printf("Can't open layout file [%s]\n", file.c_str());
		return;
            }
            fp = ::fopen(file2.c_str(), "r");
	}
	char line[255];
	int id;
	float x, y;
	float minx, miny, maxx, maxy;
	minx = miny = 1e9;
	maxx = maxy = -1e9;
	
	fgets(line, 255, fp);
	while(!feof(fp)) {
		sscanf(line,"%d\t%f\t%f", &id, &x, &y);
		if(id>=0 && id<(int) graph->numNodes()) {
			setLocation(id, x, y);
			minx = fmin(x, minx);
			miny = fmin(y, miny);
			maxx = fmax(x, maxx);
			maxy = fmax(y, maxy);
		}
		fgets(line, 255, fp);
	}
	
	fclose(fp);
	float maxdim = fmax(maxx-minx, maxy-miny);
	for(unsigned int i=0;i<graph->numNodes();i++) {
		float x, y;
		getLocation(i, x, y);
		x = (x-minx)/(maxdim);
		y = (y-miny)/(maxdim);
		setLocation(i, x, y);
	}
	printf("[IO] Loaded layout from file %s\n", file.c_str());
}

void Layout::save() {
	string layoutFile = getPropertyString("File");
	FILE *fp = ::fopen(layoutFile.c_str(),"w");
	if(!fp) {
		printf("Can't open layout file [%s]\n", layoutFile.c_str());
		return;
	}
	for(unsigned int i=0;i<graph->numNodes();i++) {
		float x, y;
		getLocation(i,x,y);
		fprintf(fp, "%d\t%f\t%f\n", i, x, y);
	}
	
	fclose(fp);
	printf("[IO] Saved Layout to file %s\n", layoutFile.c_str());
}

void Layout::updated() {
	if(controller) controller->layoutUpdated();
}

